import logging
import math
import gym
from gym import spaces
from gym.utils import seeding
import numpy as np
import random
import os
import torch
import torch.nn as nn
import json
import copy

import pandas as pd
# from Comparison_Algorithm.Highest_Bitrate import Env_Alg as HB
from Comparison_Algorithm.State_of_art_algorithm import Env_Alg as SA

from queue import Queue

# DIR = "data_test"
DIR = "data_train"

logger = logging.getLogger(__name__)

class DataSet():
    def __init__(self):
        # 二维向量，横轴是分片，纵轴是时隙
        self.bitratelevel = []
        self.bitrateInfo = []
        self.buffer = []
        self.FovRecord = []
        self.rebuffer_time = []
        self.throughput = []
        self.pause_total = []
        self.name = ""



    def Fetch_data_from_file(self,filepath,filename):
        pos = []
        file = filepath+filename
        with open(file, 'r') as file_to_read:
            while True:
                lines = file_to_read.readline()  # 整行读取数据
                if not lines:
                    break
                p_tmp = [float(i) for i in lines.split(',')]  # 将整行数据分割处理，如果分割符是空格，括号里就不用传入参数，如果是逗号， 则传入‘，'字符。
                pos.append(p_tmp)  # 添加新读取的数据
            pos = np.array(pos)
        if filename == "bitrateLevel.txt":
            self.bitratelevel = pos
        elif filename == "bitrateInfo.txt":
            self.bitrateInfo = pos
        elif filename == "throughput.txt":
            self.throughput = pos
        elif filename == "buffer.txt":
            self.buffer = pos
        elif filename == "FovRecord.txt":
            self.FovRecord = pos
        elif filename == "pause_total.txt":
            self.pause_total = pos
        elif filename == "rebuffer_time.txt":
            self.rebuffer_time = pos

class TiledVideo(gym.Env):
    metadata = {
        'render.modes': ['human', 'rgb_array'],
        'video.frames_per_second' : 50
    }

    def __init__(self):

        self.video = np.array([0,1,2,3,4,5]) # 2*2 tiled  不懂 video如何
        self.action_space = spaces.Discrete(4*4*4*4*4*4) # 4^6 每一个tile可以选择4种码率
        #self.action_space = spaces.MultiDiscrete(4 * np.ones((4,)))
        # 前六个FoV，中6个buffer，后6个吞吐量
        self.observation_space = spaces.Discrete(13) # 6 FoV+1 buffer
        # self.observation_space.n = 14
        #self.observation_space = spaces.MultiDiscrete(4 * np.ones((4,)))
        self.rng = np.random.RandomState(1234) # 1234是随机数种子
        self.S_INFO = 6 #5 # 6 #5
        self.S_LEN = 8
        self.state = np.zeros([self.S_INFO, self.S_LEN])
        self.ep_steps_max = 0 #
        self.video_slot = 0
        self.record_bitratelevel = []
        self.dirs = [] # 存文件数据文件名的
        # self.tile_adjacent_relation = {0:[1,2],
        #                                1:[0,3],
        #                                2:[0,3],
        #                                3:[1,2]}
        self.tile_adjacent_relation = {0:[2,3,4,5],
                                       1:[2,3,4,5],
                                       2:[0,1,4,5],
                                       3:[0,1,4,5],
                                       4:[0,1,2,3],
                                       5:[0,1,2,3]}  # tile与其他tile的关联程度，是自行设计的
        self.buffer = [0,0,0,0,0,0]  # 每一个tile有一个buffer
        self.rebuffer_event = [0,0,0,0,0,0] # rebuffer事件
        self.rebuffer_record_time = [0, 0, 0, 0, 0, 0]
        # 读取数据集信息
        # self.dataset = DataSet() # 数据存储类
        self.dataset_all = [DataSet() for i in range(len(os.listdir("./"+DIR)))]
        self.dataset = DataSet()
        self.load_data_all()
        self.throught_data = []
        self.throught_data_path = []
        self.load_throughtput_dataset()
        self.use_throughtput = []
        self.dataset_flag = 0
        self.FoV_data_sample = []
        self.state_rate_mapping = {0: 0.15,
                              1: 2.4,
                              2: 6.4,
                              3: 16}

        self.FoV_Adjacent = {0:[2,3,4,5],
                        1:[2,3,4,5],
                        2:[0,1,4,5],
                        3:[0,1,4,5],
                        4:[0,1,2,3],
                        5:[0,1,2,3]}

        # Comparison Algorithm
        self.HB_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.DP_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.LB_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.BOLA_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.Buffer_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.Throughput_Comparison = SA(self.state_rate_mapping, self.FoV_Adjacent)
        # record
        self.past_bitrate = Queue(maxsize=self.S_LEN) # 上一个帧的比特率
        self.past_throughout = [] #Queue(maxsize=self.S_LEN)

    def FoV_data_generation(self):
        self.FoV_data_sample = [[0,0,0,1,1,0],
                                [0,0,0,1,1,0],
                                [1,0,0,0,0,0],
                                [1,0,0,0,0,0],
                                [0,0,1,0,0,0],
                                [0,0,1,0,1,0],
                                [0,0,0,1,1,0],
                                [0,0,0,1,1,0],
                                [0,0,0,0,1,0],
                                [0,0,0,0,1,0],
                                [0,0,0,0,0,1],
                                [1, 0, 0, 0, 0, 1],
                                [1, 0, 0, 0, 0, 1],
                                [1, 0, 0, 0, 0, 0],
                                [1, 0, 1, 0, 0, 0],
                                [1, 0, 1, 0, 0, 0],
                                [0, 0, 1, 0, 1, 0],
                                [0, 0, 1, 0, 1, 0],
                                [0, 1, 0, 0, 1, 0],
                                [0, 1, 0, 0, 1, 0],
                                [0, 0, 0, 1, 0, 0],
                                [0, 0, 0, 1, 0, 0],
                                [0, 0, 0, 1, 0, 1],
                                [0, 0, 0, 1, 0, 1],
                                ]
        self.FoV_data_sample = np.array(self.FoV_data_sample)
        return self.FoV_data_sample

    def load_throughtput_dataset(self):
        # 3G速度太慢了
        # dataset_dir = "./Network_Trace/3Glogs/"
        # root_3Gdata = os.listdir(dataset_dir)
        # for i in range(len(root_3Gdata)):
        #     data_path = root_3Gdata[i]
        #     with open(dataset_dir+data_path,'r') as load_f:
        #         load_dict = json.load(load_f)
        #         #load_dict[i]["bandwidth_kbps"]
        #         for j in range(len(load_dict)):
        #             load_dict[j] = load_dict[j]["bandwidth_kbps"]
        #     self.throught_data.append(load_dict)
        #     self.throught_data_path.append(data_path)

        # dataset_dir = "./Network_Trace/4Glogs/"
        # #dataset_dir = "./Network_Trace/4G_evaluation_logs/"
        # root_4Gdata = os.listdir(dataset_dir)
        # for i in range(len(root_4Gdata)):
        #     data_path = root_4Gdata[i]
        #     with open(dataset_dir+data_path,'r') as load_f:
        #         load_dict = json.load(load_f)
        #         #load_dict[i]["bandwidth_kbps"]
        #         for j in range(len(load_dict)):
        #             load_dict[j] = load_dict[j]["bandwidth_kbps"]
        #
        #     self.throught_data.append(load_dict)
        #     self.throught_data_path.append(data_path)

        dataset_dir = "./Network_Trace/5Glogs/"
        root_5Gdata = os.listdir(dataset_dir)
        for i in range(len(root_5Gdata)):
            data_path = root_5Gdata[i]
            with open(dataset_dir + data_path, 'r') as load_f:
                load_dict = json.load(load_f)
                # load_dict[i]["bandwidth_kbps"]
                load_dict_list = []
                for j in range(len(load_dict)):
                    load_dict_list.append(load_dict[str(j)])

            self.throught_data.append(load_dict_list)
            self.throught_data_path.append(data_path)


    def load_data_all(self):
        # self.dirs = os.listdir("D:\Project_Python\ABR\option-critic-pytorch-master\data_train")
        self.dirs = os.listdir("./"+DIR)

        # 全读进内存
        for i in range(len(self.dirs)):
            dir_path = DIR + "/" + self.dirs[i] + "/"
            self.dataset_all[i].name = dir_path
            self.dataset_all[i].Fetch_data_from_file(dir_path, "bitrateLevel.txt")
            self.dataset_all[i].Fetch_data_from_file(dir_path, "bitrateInfo.txt")
            self.dataset_all[i].Fetch_data_from_file(dir_path, "throughput.txt")
            self.dataset_all[i].Fetch_data_from_file(dir_path, "buffer.txt")
            self.dataset_all[i].Fetch_data_from_file(dir_path, "FovRecord.txt")
            self.dataset_all[i].Fetch_data_from_file(dir_path, "pause_total.txt")
            self.dataset_all[i].Fetch_data_from_file(dir_path, "rebuffer_time.txt")

    def load_data_one(self):
        # dir_path = DIR + "/" + random.choice(self.dirs) + "/"
        self.dataset = random.choice(self.dataset_all)
        print(self.dataset.name)

    # def load_excel_5G(self):
    #     dirname = ""
    #     filename = ".xls"
    #     from Tools.File_processor import search
    #     file_list = search('./Network_Trace/log/',".xls")
    #
    #     for i in range(len(file_list)):
    #         file_list[i] = file_list[i].replace('\\','/')
    #         data = pd.read_excel(file_list[i])
    #         print('显示表格的属性:', data.shape)  # 打印显示表格的属性，几行几列
    #         print('显示表格的列名:', data.columns)  # 打印显示表格有哪些列名
    #         # head() 默认显示前5行，可在括号内填写要显示的条数
    #         print('显示表格前三行:', data.head(1))
    #         print('--------------------------华丽的分割线----------------------------')
    #         # tail() 默认显示后5行，可在括号内填写要显示的条数
    #         print('显示表格后五行:', data.tail())

    def seed(self, seed=None):
        return self._seed(seed)

    def _seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def reset(self):
        self.state = np.zeros([self.S_INFO,self.S_LEN])
        # self.state = [0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0]# *2
        self.buffer = [0,0,0,0,0,0]
        self.past_throughout = [0,0,0,0,0,0,0,0]
        # for i in range(self.S_LEN):
        #     self.past_throughout.put(0)
        # self.last_bitrate = []
        self.last_bitrate = [] # [[0,0,0,0]] # 4个tile 1个时隙
        self.last_throughout = []
        self.rebuffer_event = [0,0,0,0,0,0]
        self.rebuffer_record_time = [0,0,0,0,0,0]
        # self.ep_steps = 0 # 没用上啊，main_ABR的程序里自己有记录
        self.record_bitratelevel = []  # 归零更新

        self.HB_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.DP_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.LB_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)
        self.BOLA_Comparison = SA(self.state_rate_mapping,self.FoV_Adjacent)

        self.load_data_one()  # 在这里读文件
        # self.use_FoV =  self.dataset.FovRecord
        self.use_FoV = self.FoV_data_generation()
        if random.random()< 0: # 0.2
            self.load_data_one()  # 在这里读文件
            self.use_throughtput = self.dataset.throughput
            self.use_FoV = self.dataset.FovRecord
            self.dataset_flag = 0
        else:
            index, self.use_throughtput = random.choice(list(enumerate(self.throught_data)))
            print(self.throught_data_path[index])
            # for i in range(len(self.use_throughtput)):
            #     self.use_throughtput[i] = self.use_throughtput[i]["bandwidth_kbps"]
            # self.use_throughtput = random.choice(self.throught_data)
            if len(self.use_FoV) < len(self.use_throughtput):
                self.use_FoV = self.extend_array(self.use_FoV,len(self.use_throughtput))
            else:
                self.use_FoV = self.use_FoV[0:len(self.use_throughtput)]
            self.dataset_flag = 1
        # self.load_excel_5G()
        # self.video_slot = 0  ## reset有两种情况，一个是视频播完，另一个是步长太大，所以不能在这个reset里归零video_slot
        return self.state

    def extend_array(self, arr, length):
        factor, fraction = divmod(length, len(arr))
        return np.concatenate([arr] * factor + [arr[:fraction]])

    def ten_to_4(self, x): # 10转4进制
        output = ""
        ret = x // 4
        leave = x % 4
        if ret == 0:
            return str(leave)
        xxx = self.ten_to_4(ret)
        output = xxx + str(leave)
        return output

    def Dimensionality_reduction(self,FoV_4_6):
        FoV_6 = [0,0,0,0,0,0]
        for i in range(6):
            FoV_6[i] = 0.5*FoV_4_6[0][i] + FoV_4_6[1][i] + FoV_4_6[2][i]

        return FoV_6

    def step(self, action, current_option,tile_id): # 将已经判断出的action current_option送入，获取reward？
        throughput = self.use_throughtput
        FoV = self.use_FoV
        done = False

        if self.dataset_flag == 0:
            throughput = throughput / 8000000
        else:  # flag = 1 kbps
            throughput = np.array(throughput) / 8000  # MBps
            throughput = np.repeat(np.expand_dims(throughput, axis=1), 6, axis=1)
            throughput = throughput + abs(np.random.standard_normal(size=[throughput.shape[0],throughput.shape[1]]))/100
            # 5G不再除以100

        throughput_mean = np.mean(throughput[self.video_slot])
        throughput_sum = np.sum(throughput[self.video_slot])
        alpha = 1.25  # 1.75 #3 #4 #2 # 3 #.5
        beta = 1  # 4 #2 # 1.5
        gamma = 15 #10
        artificial_main = 1
        artificial_main_near = 0.6
        artificial_not_main = 0.3
        artificial_duimian = -10 #-0.2 #-5 # 当作多传数据的惩罚？
        if tile_id != -1:
            # bitrate
            #bitrate = self.state[]
            action = action.detach().item()
            bitrate_each_tile_weight = (action) * self.state[4][tile_id]  #artificial_range_1s[i])
            # rebuffer
            rebuffer_event = 0
            rebuffer_flag = 0
            rebuffer_record_time = 0
            if self.buffer[tile_id] < 1:
                self.buffer[tile_id] += throughput[self.video_slot][tile_id] / self.state_rate_mapping[action]
                if self.buffer[tile_id] < 1:
                    rebuffer_event += 1 - self.buffer[tile_id]
                    rebuffer_flag = 1
                    rebuffer_record_time += 1
                    # self.buffer[i] = 1
            else:
                self.buffer[tile_id] = 1 + throughput[self.video_slot][tile_id] / self.state_rate_mapping[action]
            if not rebuffer_flag:
                self.buffer[tile_id] = self.buffer[tile_id] - 1 # (np.array(self.buffer) - 1).tolist()   # 模拟buffer过程
            buffer_penalty = 3 if self.buffer[tile_id]>9.5 else 0
            reward = alpha * bitrate_each_tile_weight - gamma * rebuffer_event - buffer_penalty

            input_buffer = np.array(copy.deepcopy(self.buffer))
            input_buffer[input_buffer > 10.5] = 10.5

            input_throughput = np.array(copy.deepcopy(self.past_throughout))

            input_throughput[0:6] = input_throughput[1:7]
            input_throughput[-1] = throughput_mean

            self.state[0, :6] = input_buffer  # .tolist()
            # return self.state, reward, done, _
            self.rebuffer_event[tile_id] = rebuffer_event
            self.rebuffer_record_time[tile_id] = rebuffer_record_time
            return self.state,reward,False,[rebuffer_event]
        else:
            action = [action[i].detach().item() for i in range(6)]
            #self.record_bitratelevel.append(self.state[0:6]) # 记录之前的码率选择

            artificial_range_1s = {}
            range_temp = [0,1,2,3,4,5]
            main_perspective = 0
            main_near = []
            artificial_range_2s = {}
            artificial_duimian = -1

            FoV_inside_bitrate_each_tile = []
            FoV_adjacency_bitrate_each_tile = []
            FoV_outside_bitrate_each_tile = []

            for i in range_temp:
                if FoV[self.video_slot][i].astype(int) == 1:
                    # count = list(FoV[self.video_slot + 1].astype(int)).count(1)
                    artificial_range_1s[i] = artificial_main  # 主视野内权重为0.8
                    FoV_inside_bitrate_each_tile.append(action[i])
                    range_temp.remove(i)
                    main_perspective = i
                    for j in self.FoV_Adjacent[i]:
                        range_temp.remove(j)
                        if FoV[self.video_slot][j].astype(int) == 1:
                            artificial_range_1s[j] = artificial_main_near# 0.5
                            main_near.append(j)
                            FoV_adjacency_bitrate_each_tile.append(action[j])
                        else:
                            artificial_range_1s[j] = artificial_not_main# 0.2
                            FoV_adjacency_bitrate_each_tile.append(action[j])

            artificial_range_1s[range_temp[0]] = artificial_duimian ## ???
            FoV_outside_bitrate_each_tile.append(action[range_temp[0]])

            from copy import deepcopy
            bitrate_each_tile_weight = []
            for i in range(6):  # 6个面
                bitrate_each_tile_weight.append((action[i]) * artificial_range_1s[i])
            bitrate_level_total = np.sum(bitrate_each_tile_weight)

            # 帧内平滑度
            # 考虑FoV的东西，这个平滑度考虑主视角和其他四片的差异
            smoothness_within_frame = 0
            smoothness_inside_FoV = 0
            smoothness_adjacency_FoV = 0
            smoothness_outside_FoV = 0

            for i in self.FoV_Adjacent[main_perspective]:
                if i in main_near:
                    smoothness_inside_FoV += abs(action[main_perspective] - action[i])
                    smoothness_within_frame += smoothness_inside_FoV # abs(action[main_perspective] - action[i])
                else:
                    smoothness_adjacency_FoV += abs(0.5 * (action[main_perspective] - action[i]))
                    smoothness_within_frame += smoothness_adjacency_FoV # abs(0.5 * (action[main_perspective] - action[i]))

            if main_perspective % 2 == 0:
                duimian = main_perspective+1
            else:
                duimian = main_perspective-1
            for i in self.FoV_Adjacent[duimian]:
                smoothness_outside_FoV += abs(action[duimian] - action[i])


            bitrate = 0
            for i in range(6):
                bitrate += action[i]
            # 1.8-0.3-0.5
            # alpha = 1.25 #1.75 #3 #4 #2 # 3 #.5
            # beta = 1 #4 #2 # 1.5
            # gamma = 10 # 12 # 8#10 # 20 #8 # 4
            # bitrate_factor=0.4 #3 # 0.8会导致全选0
            # reward = alpha * bitrate_level_total - (bitrate_factor* bitrate) - beta * smoothness_within_frame - gamma*rebuffer_event
            # reward = alpha * bitrate_level_total - bitrate_factor * bitrate - gamma * rebuffer_event
            # reward = alpha * bitrate_level_total - gamma * rebuffer_event

            reward = alpha * bitrate_level_total - current_option* beta * smoothness_within_frame - gamma * np.sum(self.rebuffer_event)
            # 用各个面的输入
            # input_throughput = [0, 0, 0, 0, 0, 0]
            if self.video_slot == 0:
                input_throughput = throughput[0]
            else:
                input_throughput = throughput[self.video_slot-1]

            reward_HB = self.HB_Comparison.Highest_Bitrate_Selection(FoV, input_throughput,alpha,beta,gamma,
                                                                     artificial_main,artificial_main_near,artificial_not_main,artificial_duimian)#,bitrate_factor)
            reward_DP = self.DP_Comparison.Dynamic_Profit(FoV[self.video_slot],FoV[self.video_slot + 1],input_throughput,
                                                          alpha,beta,gamma,artificial_main,artificial_main_near,artificial_not_main,artificial_duimian)
            reward_LB = self.LB_Comparison.Lowest_Bitrate_Selection(FoV, input_throughput,alpha,beta,gamma,
                                                                     artificial_main,artificial_main_near,artificial_not_main,artificial_duimian)
            reward_Buffer = self.Buffer_Comparison.Buffer_based(FoV, input_throughput, alpha, beta, gamma,
                                                                    artificial_main, artificial_main_near,
                                                                    artificial_not_main, artificial_duimian)
            reward_Throughput = self.Throughput_Comparison.Throughtput_based(FoV, input_throughput, alpha, beta, gamma,
                                                                    artificial_main, artificial_main_near,
                                                                    artificial_not_main, artificial_duimian)
            # reward_BOLA = self.BOLA_Comparison.Bola(FoV[self.video_slot],input_throughput,alpha,beta,gamma,
                                                    #artificial_main,artificial_main_near,artificial_not_main,artificial_duimian)
            #with open(DIR+"_result.txt","a") as f:
            #    f.write("FoV2: "+str(FoV[self.video_slot+1])+",  因FoV做的决策: " + str(action)+ ",   option: " + str(current_option) +  "\n")

            self.video_slot += 1
            # 123
            if self.video_slot >= self.use_FoV.shape[0]-2 or self.video_slot >= self.ep_steps_max:
                done = True
                self.video_slot = 0

            FoV_state = FoV[self.video_slot]
            input_buffer = np.array(copy.deepcopy(self.buffer))
            # input_buffer[input_buffer > 1] = 1

            self.past_throughout[0:6] = self.past_throughout[1:7]
            self.past_throughout[-1] = throughput_mean

            self.state[0,:6] = input_buffer#.tolist()
            self.state[1,:8] = self.past_throughout
            self.state[2, :4] = [0.15,2.4,6.4,16]
            self.state[3,-1] = self.video_slot/len(self.dataset.throughput)
            artificial_range_1s = {}
            range_temp = [0,1,2,3,4,5]
            main_perspective = 0
            main_near = []
            for i in range_temp:
                if FoV_state[i].astype(int) == 1:
                    # count = list(FoV[self.video_slot + 1].astype(int)).count(1)
                    artificial_range_1s[i] = artificial_main  # 主视野内权重为0.8
                    range_temp.remove(i)
                    main_perspective = i
                    for j in self.FoV_Adjacent[i]:
                        range_temp.remove(j)
                        if FoV_state[j].astype(int) == 1:
                            artificial_range_1s[j] = artificial_main_near  # 0.5
                            main_near.append(j)
                        else:
                            artificial_range_1s[j] = artificial_not_main  # 0.2
            artificial_range_1s[range_temp[0]] = artificial_duimian
            FoV_weight = np.array([artificial_range_1s[0],artificial_range_1s[1],
                                  artificial_range_1s[2],artificial_range_1s[3],
                                  artificial_range_1s[4],artificial_range_1s[5]])
            self.state[4, :6] = FoV_weight
            self.state[5, :6] = action

            latency = 0;data_amount = 0;##这俩从系统上测吧？
            _ = [bitrate_level_total,smoothness_within_frame,np.sum(self.rebuffer_event), latency, data_amount, np.sum(self.rebuffer_record_time),
                 FoV_inside_bitrate_each_tile, FoV_adjacency_bitrate_each_tile, FoV_outside_bitrate_each_tile,
                    smoothness_inside_FoV, smoothness_adjacency_FoV, smoothness_outside_FoV,
                 reward_HB,reward_DP,reward_LB,1,reward_Buffer,reward_Throughput]# reward_HB
            return self.state, reward, done, _

# Global
DP_rebuffer_epi = []
DP_bitrate_epi = []
DP_smoothness_epi = []
DP_reward_list = []
DP_rebuffer_time_epi = []
DP_option_list = []
DP_FoV_inside_bitrate_epi = []
DP_FoV_adjacency_bitrate_epi = []
DP_FoV_outside_bitrate_epi = []
DP_smoothness_inside_FoV = []
DP_smoothness_adjacency_FoV = []
DP_smoothness_outside_FoV = []
DP_bitrate_level_number_epi = []

HB_rebuffer_epi = []
HB_bitrate_epi = []
HB_smoothness_epi = []
HB_reward_list = []
HB_rebuffer_time_epi = []
HB_option_list = []
HB_FoV_inside_bitrate_epi = []
HB_FoV_adjacency_bitrate_epi = []
HB_FoV_outside_bitrate_epi = []
HB_smoothness_inside_FoV = []
HB_smoothness_adjacency_FoV = []
HB_smoothness_outside_FoV = []
HB_bitrate_level_number_epi = []

LB_rebuffer_epi = []
LB_bitrate_epi = []
LB_smoothness_epi = []
LB_reward_list = []
LB_rebuffer_time_epi = []
LB_option_list = []
LB_FoV_inside_bitrate_epi = []
LB_FoV_adjacency_bitrate_epi = []
LB_FoV_outside_bitrate_epi = []
LB_smoothness_inside_FoV = []
LB_smoothness_adjacency_FoV = []
LB_smoothness_outside_FoV = []
LB_bitrate_level_number_epi = []

Buffer_rebuffer_epi = []
Buffer_bitrate_epi = []
Buffer_smoothness_epi = []
Buffer_reward_list = []
Buffer_rebuffer_time_epi = []
Buffer_option_list = []
Buffer_FoV_inside_bitrate_epi = []
Buffer_FoV_adjacency_bitrate_epi = []
Buffer_FoV_outside_bitrate_epi = []
Buffer_smoothness_inside_FoV = []
Buffer_smoothness_adjacency_FoV = []
Buffer_smoothness_outside_FoV = []
Buffer_bitrate_level_number_epi = []

Throughput_rebuffer_epi = []
Throughput_bitrate_epi = []
Throughput_smoothness_epi = []
Throughput_reward_list = []
Throughput_rebuffer_time_epi = []
Throughput_option_list = []
Throughput_FoV_inside_bitrate_epi = []
Throughput_FoV_adjacency_bitrate_epi = []
Throughput_FoV_outside_bitrate_epi = []
Throughput_smoothness_inside_FoV = []
Throughput_smoothness_adjacency_FoV = []
Throughput_smoothness_outside_FoV = []
Throughput_bitrate_level_number_epi = []

def algorithm_test(TileVideo):
    throughput = TileVideo.use_throughtput
    FoV = TileVideo.use_FoV
    done = False

    if TileVideo.dataset_flag == 0:
        throughput = throughput / 8000000
    else:  # flag = 1 kbps
        throughput = np.array(throughput) / 8000  # MBps
        throughput = np.repeat(np.expand_dims(throughput, axis=1), 6, axis=1)
        throughput = throughput + np.random.standard_normal(size=[throughput.shape[0], throughput.shape[1]])*3
        # 5G不再除以100
    throughput[throughput <= 1] = np.mean(throughput[throughput > 1])


    artificial_main = 1
    artificial_main_near = 0.2
    artificial_not_main = 0.1
    artificial_duimian = 0

    alpha = 1.75  # 3 #4 #2 # 3 #.5
    beta = 1  # 4 #2 # 1.5
    gamma = 10  # 12 # 8#10 # 20 #8 # 4

    DP_rebuffer_step = []
    DP_bitrate_step = []
    DP_smoothness_step = []
    DP_reward_step = 0
    DP_rebuffer_time_step = []
    DP_FoV_inside_bitrate_step = []
    DP_FoV_adjacency_bitrate_step = []
    DP_FoV_outside_bitrate_step = []
    DP_smoothness_inside_FoV_step = []
    DP_smoothness_adjacency_FoV_step = []
    DP_smoothness_outside_FoV_step = []
    DP_bitrate_level_number_step = []

    HB_rebuffer_step = []
    HB_bitrate_step = []
    HB_smoothness_step = []
    HB_reward_step = 0
    HB_rebuffer_time_step = []
    HB_FoV_inside_bitrate_step = []
    HB_FoV_adjacency_bitrate_step = []
    HB_FoV_outside_bitrate_step = []
    HB_smoothness_inside_FoV_step = []
    HB_smoothness_adjacency_FoV_step = []
    HB_smoothness_outside_FoV_step = []
    HB_bitrate_level_number_step = []

    LB_rebuffer_step = []
    LB_bitrate_step = []
    LB_smoothness_step = []
    LB_reward_step = 0
    LB_rebuffer_time_step = []
    LB_FoV_inside_bitrate_step = []
    LB_FoV_adjacency_bitrate_step = []
    LB_FoV_outside_bitrate_step = []
    LB_smoothness_inside_FoV_step = []
    LB_smoothness_adjacency_FoV_step = []
    LB_smoothness_outside_FoV_step = []
    LB_bitrate_level_number_step = []

    Buffer_rebuffer_step = []
    Buffer_bitrate_step = []
    Buffer_smoothness_step = []
    Buffer_reward_step = 0
    Buffer_rebuffer_time_step = []
    Buffer_FoV_inside_bitrate_step = []
    Buffer_FoV_adjacency_bitrate_step = []
    Buffer_FoV_outside_bitrate_step = []
    Buffer_smoothness_inside_FoV_step = []
    Buffer_smoothness_adjacency_FoV_step = []
    Buffer_smoothness_outside_FoV_step = []
    Buffer_bitrate_level_number_step = []

    Throughput_rebuffer_step = []
    Throughput_bitrate_step = []
    Throughput_smoothness_step = []
    Throughput_reward_step = 0
    Throughput_rebuffer_time_step = []
    Throughput_FoV_inside_bitrate_step = []
    Throughput_FoV_adjacency_bitrate_step = []
    Throughput_FoV_outside_bitrate_step = []
    Throughput_smoothness_inside_FoV_step = []
    Throughput_smoothness_adjacency_FoV_step = []
    Throughput_smoothness_outside_FoV_step = []
    Throughput_bitrate_level_number_step = []

    for i in range(len(TileVideo.use_FoV)-1):
        TileVideo.video_slot = i
        if TileVideo.video_slot == 0:
            input_throughput = throughput[0]
        else:
            input_throughput = throughput[TileVideo.video_slot - 1]
        reward_HB = TileVideo.HB_Comparison.Highest_Bitrate_Selection(FoV, input_throughput, alpha, beta, gamma,
                                                                 artificial_main, artificial_main_near, artificial_not_main,
                                                                 artificial_duimian)  # ,bitrate_factor)
        reward_DP = TileVideo.DP_Comparison.Dynamic_Profit(FoV[TileVideo.video_slot], FoV[TileVideo.video_slot + 1], input_throughput,
                                                      alpha, beta, gamma, artificial_main, artificial_main_near,
                                                      artificial_not_main, artificial_duimian)
        reward_LB = TileVideo.LB_Comparison.Lowest_Bitrate_Selection(FoV, input_throughput, alpha, beta, gamma,
                                                                artificial_main, artificial_main_near, artificial_not_main,
                                                                artificial_duimian)
        reward_Buffer = TileVideo.Buffer_Comparison.Buffer_based(FoV, input_throughput, alpha, beta, gamma,
                                                            artificial_main, artificial_main_near,
                                                            artificial_not_main, artificial_duimian)
        reward_Throughput = TileVideo.Throughput_Comparison.Throughtput_based(FoV, input_throughput, alpha, beta, gamma,
                                                                         artificial_main, artificial_main_near,
                                                                         artificial_not_main, artificial_duimian)
        HB_rebuffer_step.append(reward_HB[3])
        HB_bitrate_step.append(reward_HB[1])
        HB_smoothness_step.append(reward_HB[2])
        HB_reward_step += reward_HB[0]
        HB_rebuffer_time_step.append(reward_HB[4])
        HB_FoV_inside_bitrate_step.append(reward_HB[5])
        HB_FoV_adjacency_bitrate_step.append(reward_HB[6])
        HB_FoV_outside_bitrate_step.append(reward_HB[7])
        HB_smoothness_inside_FoV_step.append(reward_HB[8])
        HB_smoothness_adjacency_FoV_step.append(reward_HB[9])
        HB_smoothness_outside_FoV_step.append(reward_HB[10])
        HB_bitrate_level_number_step.append(reward_HB[5])
        HB_bitrate_level_number_step[-1].extend(reward_HB[6])
        HB_bitrate_level_number_step[-1].extend(reward_HB[7])

        DP_rebuffer_step.append(reward_DP[3])
        DP_bitrate_step.append(reward_DP[1])
        DP_smoothness_step.append(reward_DP[2])
        DP_reward_step += reward_DP[0]
        DP_rebuffer_time_step.append(reward_DP[4])
        DP_FoV_inside_bitrate_step.append(reward_DP[5])
        DP_FoV_adjacency_bitrate_step.append(reward_DP[6])
        DP_FoV_outside_bitrate_step.append(reward_DP[7])
        DP_smoothness_inside_FoV_step.append(reward_DP[8])
        DP_smoothness_adjacency_FoV_step.append(reward_DP[9])
        DP_smoothness_outside_FoV_step.append(reward_DP[10])
        DP_bitrate_level_number_step.append(reward_DP[5])
        DP_bitrate_level_number_step[-1].extend(reward_DP[6])
        DP_bitrate_level_number_step[-1].extend(reward_DP[7])

        LB_rebuffer_step.append(reward_LB[3])
        LB_bitrate_step.append(reward_LB[1])
        LB_smoothness_step.append(reward_LB[2])
        LB_reward_step += reward_LB[0]
        LB_rebuffer_time_step.append(reward_LB[4])
        LB_FoV_inside_bitrate_step.append(reward_LB[5])
        LB_FoV_adjacency_bitrate_step.append(reward_LB[6])
        LB_FoV_outside_bitrate_step.append(reward_LB[7])
        LB_smoothness_inside_FoV_step.append(reward_LB[8])
        LB_smoothness_adjacency_FoV_step.append(reward_LB[9])
        LB_smoothness_outside_FoV_step.append(reward_LB[10])
        LB_bitrate_level_number_step.append(reward_LB[5])
        LB_bitrate_level_number_step[-1].extend(reward_LB[6])
        LB_bitrate_level_number_step[-1].extend(reward_LB[7])

        Buffer_rebuffer_step.append(reward_Buffer[3])
        Buffer_bitrate_step.append(reward_Buffer[1])
        Buffer_smoothness_step.append(reward_Buffer[2])
        Buffer_reward_step += reward_Buffer[0]
        Buffer_rebuffer_time_step.append(reward_Buffer[4])
        Buffer_FoV_inside_bitrate_step.append(reward_Buffer[5])
        Buffer_FoV_adjacency_bitrate_step.append(reward_Buffer[6])
        Buffer_FoV_outside_bitrate_step.append(reward_Buffer[7])
        Buffer_smoothness_inside_FoV_step.append(reward_Buffer[8])
        Buffer_smoothness_adjacency_FoV_step.append(reward_Buffer[9])
        Buffer_smoothness_outside_FoV_step.append(reward_Buffer[10])
        Buffer_bitrate_level_number_step.append(reward_Buffer[5])
        Buffer_bitrate_level_number_step[-1].extend(reward_Buffer[6])
        Buffer_bitrate_level_number_step[-1].extend(reward_Buffer[7])

        Throughput_rebuffer_step.append(reward_Throughput[3])
        Throughput_bitrate_step.append(reward_Throughput[1])
        Throughput_smoothness_step.append(reward_Throughput[2])
        Throughput_reward_step += reward_Throughput[0]
        Throughput_rebuffer_time_step.append(reward_Throughput[4])
        Throughput_FoV_inside_bitrate_step.append(reward_Throughput[5])
        Throughput_FoV_adjacency_bitrate_step.append(reward_Throughput[6])
        Throughput_FoV_outside_bitrate_step.append(reward_Throughput[7])
        Throughput_smoothness_inside_FoV_step.append(reward_Throughput[8])
        Throughput_smoothness_adjacency_FoV_step.append(reward_Throughput[9])
        Throughput_smoothness_outside_FoV_step.append(reward_Throughput[10])
        Throughput_bitrate_level_number_step.append(reward_Throughput[5])
        Throughput_bitrate_level_number_step[-1].extend(reward_Throughput[6])
        Throughput_bitrate_level_number_step[-1].extend(reward_Throughput[7])

    ep_steps = len(TileVideo.use_FoV)
    DP_rebuffer_epi.append(np.sum(DP_rebuffer_step))
    DP_bitrate_epi.append(np.mean(DP_bitrate_step))
    DP_smoothness_epi.append(np.mean(DP_smoothness_step))
    DP_reward_list.append(DP_reward_step / ep_steps)
    DP_rebuffer_time_epi.append(np.sum(DP_rebuffer_time_step))
    DP_FoV_inside_bitrate_epi.append(np.mean(DP_FoV_inside_bitrate_step))
    DP_FoV_adjacency_bitrate_epi.append(np.mean(DP_FoV_adjacency_bitrate_step))
    DP_FoV_outside_bitrate_epi.append(np.mean(DP_FoV_outside_bitrate_step))
    DP_smoothness_inside_FoV.append(np.mean(DP_smoothness_inside_FoV_step))
    DP_smoothness_adjacency_FoV.append(np.mean(DP_smoothness_adjacency_FoV_step))
    DP_smoothness_outside_FoV.append(np.mean(DP_smoothness_outside_FoV_step))
    DP_bitrate_level_number_epi.append(DP_bitrate_level_number_step)

    HB_rebuffer_epi.append(np.sum(HB_rebuffer_step))
    HB_bitrate_epi.append(np.mean(HB_bitrate_step))
    HB_smoothness_epi.append(np.mean(HB_smoothness_step))
    HB_reward_list.append(HB_reward_step / ep_steps)
    HB_rebuffer_time_epi.append(np.sum(HB_rebuffer_time_step))
    HB_FoV_inside_bitrate_epi.append(np.mean(HB_FoV_inside_bitrate_step))
    HB_FoV_adjacency_bitrate_epi.append(np.mean(HB_FoV_adjacency_bitrate_step))
    HB_FoV_outside_bitrate_epi.append(np.mean(HB_FoV_outside_bitrate_step))
    HB_smoothness_inside_FoV.append(np.mean(HB_smoothness_inside_FoV_step))
    HB_smoothness_adjacency_FoV.append(np.mean(HB_smoothness_adjacency_FoV_step))
    HB_smoothness_outside_FoV.append(np.mean(HB_smoothness_outside_FoV_step))
    HB_bitrate_level_number_epi.append(HB_bitrate_level_number_step)

    LB_rebuffer_epi.append(np.sum(LB_rebuffer_step).astype(np.float))
    LB_bitrate_epi.append(np.mean(LB_bitrate_step))
    LB_smoothness_epi.append(np.mean(LB_smoothness_step))
    LB_reward_list.append(LB_reward_step / ep_steps)
    LB_rebuffer_time_epi.append(np.sum(LB_rebuffer_time_step))
    LB_FoV_inside_bitrate_epi.append(np.mean(LB_FoV_inside_bitrate_step))
    LB_FoV_adjacency_bitrate_epi.append(np.mean(LB_FoV_adjacency_bitrate_step))
    LB_FoV_outside_bitrate_epi.append(np.mean(LB_FoV_outside_bitrate_step))
    LB_smoothness_inside_FoV.append(np.mean(LB_smoothness_inside_FoV_step))
    LB_smoothness_adjacency_FoV.append(np.mean(LB_smoothness_adjacency_FoV_step))
    LB_smoothness_outside_FoV.append(np.mean(LB_smoothness_outside_FoV_step))
    LB_bitrate_level_number_epi.append(LB_bitrate_level_number_step)

    Buffer_rebuffer_epi.append(np.sum(Buffer_rebuffer_step).astype(np.float))
    Buffer_bitrate_epi.append(np.mean(Buffer_bitrate_step))
    Buffer_smoothness_epi.append(np.mean(Buffer_smoothness_step))
    Buffer_reward_list.append(Buffer_reward_step / ep_steps)
    Buffer_rebuffer_time_epi.append(np.sum(Buffer_rebuffer_time_step))
    Buffer_FoV_inside_bitrate_epi.append(np.mean(Buffer_FoV_inside_bitrate_step))
    Buffer_FoV_adjacency_bitrate_epi.append(np.mean(Buffer_FoV_adjacency_bitrate_step))
    Buffer_FoV_outside_bitrate_epi.append(np.mean(Buffer_FoV_outside_bitrate_step))
    Buffer_smoothness_inside_FoV.append(np.mean(Buffer_smoothness_inside_FoV_step))
    Buffer_smoothness_adjacency_FoV.append(np.mean(Buffer_smoothness_adjacency_FoV_step))
    Buffer_smoothness_outside_FoV.append(np.mean(Buffer_smoothness_outside_FoV_step))
    Buffer_bitrate_level_number_epi.append(Buffer_bitrate_level_number_step)

    Throughput_rebuffer_epi.append(np.sum(Throughput_rebuffer_step).astype(np.float))
    Throughput_bitrate_epi.append(np.mean(Throughput_bitrate_step))
    Throughput_smoothness_epi.append(np.mean(Throughput_smoothness_step))
    Throughput_reward_list.append(Throughput_reward_step / ep_steps)
    Throughput_rebuffer_time_epi.append(np.sum(Throughput_rebuffer_time_step))
    Throughput_FoV_inside_bitrate_epi.append(np.mean(Throughput_FoV_inside_bitrate_step))
    Throughput_FoV_adjacency_bitrate_epi.append(np.mean(Throughput_FoV_adjacency_bitrate_step))
    Throughput_FoV_outside_bitrate_epi.append(np.mean(Throughput_FoV_outside_bitrate_step))
    Throughput_smoothness_inside_FoV.append(np.mean(Throughput_smoothness_inside_FoV_step))
    Throughput_smoothness_adjacency_FoV.append(np.mean(Throughput_smoothness_adjacency_FoV_step))
    Throughput_smoothness_outside_FoV.append(np.mean(Throughput_smoothness_outside_FoV_step))
    Throughput_bitrate_level_number_epi.append(Throughput_bitrate_level_number_step)

if __name__=="__main__":
    env = TiledVideo()
    env.seed(3)
    time_slot = 400
    for i in range(time_slot):
        env.reset()
        algorithm_test(env)
    import scipy.io as sio
    import time
    mat_name = "Comparison_data" + time.strftime('%Y-%m-%d %H:%M:%S',
                                      time.localtime(int(round(time.time() * 1000)) / 1000)) + ".mat"
    mat_name = mat_name.replace(' ', '_')
    mat_name = mat_name.replace('-', '_')
    mat_name = mat_name.replace(':', '_')
    sio.savemat(mat_name, {"DP_rebuffer_epi": DP_rebuffer_epi,
                           "DP_bitrate_epi": DP_bitrate_epi,
                           "DP_smoothness_epi": DP_smoothness_epi,
                           "DP_reward_list": DP_reward_list,
                           "HB_rebuffer_epi": HB_rebuffer_epi,
                           "HB_bitrate_epi": HB_bitrate_epi,
                           "HB_smoothness_epi": HB_smoothness_epi,
                           "HB_reward_list": HB_reward_list,
                           "LB_rebuffer_epi": LB_rebuffer_epi,
                           "LB_bitrate_epi": LB_bitrate_epi,
                           "LB_smoothness_epi": LB_smoothness_epi,
                           "LB_reward_list": LB_reward_list,
                           "DP_FoV_inside_bitrate_epi": DP_FoV_inside_bitrate_epi,
                           "DP_FoV_adjacency_bitrate_epi": DP_FoV_adjacency_bitrate_epi,
                           "DP_FoV_outside_bitrate_epi": DP_FoV_outside_bitrate_epi,
                           "DP_smoothness_inside_FoV": DP_smoothness_inside_FoV,
                           "DP_smoothness_adjacency_FoV": DP_smoothness_adjacency_FoV,
                           "DP_smoothness_outside_FoV": DP_smoothness_outside_FoV,
                           "HB_FoV_inside_bitrate_epi": HB_FoV_inside_bitrate_epi,
                           "HB_FoV_adjacency_bitrate_epi": HB_FoV_adjacency_bitrate_epi,
                           "HB_FoV_outside_bitrate_epi": HB_FoV_outside_bitrate_epi,
                           "HB_smoothness_inside_FoV": HB_smoothness_inside_FoV,
                           "HB_smoothness_adjacency_FoV": HB_smoothness_adjacency_FoV,
                           "HB_smoothness_outside_FoV": HB_smoothness_outside_FoV,
                           "LB_FoV_inside_bitrate_epi": LB_FoV_inside_bitrate_epi,
                           "LB_FoV_adjacency_bitrate_epi": LB_FoV_adjacency_bitrate_epi,
                           "LB_FoV_outside_bitrate_epi": LB_FoV_outside_bitrate_epi,
                           "LB_smoothness_inside_FoV": LB_smoothness_inside_FoV,
                           "LB_smoothness_adjacency_FoV": LB_smoothness_adjacency_FoV,
                           "LB_smoothness_outside_FoV": LB_smoothness_outside_FoV,
                           "DP_rebuffer_time_epi": DP_rebuffer_time_epi,
                           "HB_rebuffer_time_epi": HB_rebuffer_time_epi,
                           "LB_rebuffer_time_epi": LB_rebuffer_time_epi,
                           "Buffer_rebuffer_epi": Buffer_rebuffer_epi,
                           "Buffer_bitrate_epi": Buffer_bitrate_epi,
                           "Buffer_smoothness_epi": Buffer_smoothness_epi,
                           "Buffer_reward_list": Buffer_reward_list,
                           "Buffer_FoV_inside_bitrate_epi": Buffer_FoV_inside_bitrate_epi,
                           "Buffer_FoV_adjacency_bitrate_epi": Buffer_FoV_adjacency_bitrate_epi,
                           "Buffer_FoV_outside_bitrate_epi": Buffer_FoV_outside_bitrate_epi,
                           "Buffer_smoothness_inside_FoV": Buffer_smoothness_inside_FoV,
                           "Buffer_smoothness_adjacency_FoV": Buffer_smoothness_adjacency_FoV,
                           "Buffer_smoothness_outside_FoV": Buffer_smoothness_outside_FoV,
                           "Buffer_rebuffer_time_epi": Buffer_rebuffer_time_epi,
                           "Throughput_rebuffer_epi": Throughput_rebuffer_epi,
                           "Throughput_bitrate_epi": Throughput_bitrate_epi,
                           "Throughput_smoothness_epi": Throughput_smoothness_epi,
                           "Throughput_reward_list": Throughput_reward_list,
                           "Throughput_FoV_inside_bitrate_epi": Throughput_FoV_inside_bitrate_epi,
                           "Throughput_FoV_adjacency_bitrate_epi": Throughput_FoV_adjacency_bitrate_epi,
                           "Throughput_FoV_outside_bitrate_epi": Throughput_FoV_outside_bitrate_epi,
                           "Throughput_smoothness_inside_FoV": Throughput_smoothness_inside_FoV,
                           "Throughput_smoothness_adjacency_FoV": Throughput_smoothness_adjacency_FoV,
                           "Throughput_smoothness_outside_FoV": Throughput_smoothness_outside_FoV,
                           "Throughput_rebuffer_time_epi": Throughput_rebuffer_time_epi,
                           "DP_bitrate_level_number_epi": DP_bitrate_level_number_epi,
                           "HB_bitrate_level_number_epi": HB_bitrate_level_number_epi,
                           "LB_bitrate_level_number_epi": LB_bitrate_level_number_epi,
                           "Buffer_bitrate_level_number_epi": Buffer_bitrate_level_number_epi,
                           "Throughput_bitrate_level_number_epi": Throughput_bitrate_level_number_epi
                           })
